﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Reflection;
using SocialLearning.CoreInterfaces;
using System.Runtime.Serialization;

namespace ArchitectureV2
{
    public class ModuleLoader
    {
        #region Fields

        private Dictionary<string, Type> moduleTypes;

        #endregion

        #region Constructor

        public ModuleLoader() { moduleTypes = new Dictionary<string, Type>(); }

        #endregion

        #region Properties

        public string[] ModuleList { get { lock (moduleTypes) { return (moduleTypes.Keys.ToArray()); } } }

        #endregion

        #region Public Methods

        public void FindModulesInPath(string path)
        {
            // Load all dynamic modules:
            foreach (string module in
                Directory.EnumerateFiles(path, "*.dll", SearchOption.TopDirectoryOnly))
            {
                FindModules(module);
            }
        }

        public void LoadFrom(string into, string from)
        {
            List<string> files = new List<string>();
            // Load all dynamic modules:
            foreach (string module in
                Directory.EnumerateFiles(from, "*.dll", SearchOption.TopDirectoryOnly))
            {
                files.Add(module);
            }
            if (files.Count > 0)
            {
                moduleTypes.Clear();
                KnownTypes.ClearTypes();
                GC.Collect();
                foreach (string module in files) { File.Move(module, into); }
                FindModulesInPath(into);
            }
        }

        public bool RemoveModule(string name)
        {
            lock (moduleTypes)
            {
                if (moduleTypes.ContainsKey(name))
                {
                    moduleTypes.Remove(name);
                    return (true);
                }
            }
            return (false);
        }

        public void FindModules(string file)
        {
            lock (moduleTypes)
            {
                Type interfaceType = typeof(I_CMA_ModuleImplementation);
                try
                {
                    // For each module in the modules directory:
                    Assembly asm = Assembly.LoadFrom(file);

                    // Scan for a class that implements the appropriate interface:
                    foreach (Type type in asm.GetTypes())
                    {
                        if (type.IsClass == true &&
                            type.IsPublic == true)
                        {
                            if (interfaceType.IsAssignableFrom(type)) // Test if the class implements the correct interface.
                            {
                                try
                                {
                                    moduleTypes.Add(type.Name, type); // Register the module.
                                }
                                catch { } // Ignore failures.
                            }
                            else
                            {
                                try
                                {
                                    foreach (Attribute attr in type.GetCustomAttributes(true))
                                    {
                                        if (attr is DataContractAttribute)
                                        {
                                            Debug.WriteLine("Added type: " + type.Name);
                                            KnownTypes.AddType(type);
                                            break;
                                        }
                                    }
                                }
                                catch { }
                            }
                        }
                    }
                }
                catch { } // Ignore faulty assemblies.
            }
        }

        public Dictionary<string, UserModule> LoadModules(I_CMA_Core core)
        {
            Dictionary<string, UserModule> mods = new Dictionary<string, UserModule>();
            lock (moduleTypes)
            {
                foreach (KeyValuePair<string, Type> pair in moduleTypes)
                {
                    I_CMA_ModuleImplementation module = null;
                    try { module = Activator.CreateInstance(pair.Value) as I_CMA_ModuleImplementation; } catch { }
                    if (module == null) { continue; }
                    try
                    {
                        module.LoadModule(core);
                        mods.Add(pair.Key, new UserModule(module));
                    }
                    catch { }
                }
            }
            return (mods);
        }

        public static void UnloadModules(Dictionary<string, UserModule> mods)
        {
            if (mods == null) { return; }
            foreach (KeyValuePair<string, UserModule> pair in mods) { pair.Value.Unload(); }
        }

        #endregion
    }
}